#pragma once

#include <iostream>

#include "TcpSocket.hpp"

#include <poll.h>

#include <sys/time.h>

static const uint16_t defaultport = 8050;

static const int fd_num_max = 64; // 具体的可监听数量

static const int defaultfd = -1;

static const int non_event = 0;

class PollServer
{
public:
    PollServer(uint16_t port = defaultport) : _port(port)
    {
        for (int i = 0; i < fd_num_max; ++i)
        {
            _event_fds[i].fd = defaultfd; // 初始化
            _event_fds[i].events = non_event;
            _event_fds[i].revents = non_event;
        }
    }
    bool Init()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        return true;
    }

    void Start()
    {
        _event_fds[0].fd = _listensock.GetFd(); // 设置关心监听套接字
        _event_fds[0].events = POLLIN;          // 设置监听套接字关心读事件 (监听将要来的连接)
        // revents 可设可不设 原因为 revents 为内核给用户的数据信息

        int timeout = 3000;

        for (;;)
        {

            int n = poll(_event_fds, fd_num_max, timeout /* timeout可硬编码 也可以设置变量*/);

            switch (n)
            {
            case 0:
                printf("Time out\n");
                break;
            case -1:
                printf("Poll Error\n");
                break;
            default:
                printf("%d fd Even Ready\n",n);
                Dispatcher(); // 若是有读事件发生则调用对应的读事件发生 Dispatcher()
                sleep(2);
                break;
            }
        }
    }

    void Accepter()
    { // 连接管理器
        std::string clientip;
        uint16_t clientport;
        int sock = _listensock.Accept(&clientip, &clientport); // 获取新连接的IP与端口
        if (sock < 0)
        {
            lg(WARNING, "Accept error");
            return;
        }
        lg(INFO, "Accept sucess %s: %d , sockfd: %d", clientip.c_str(), clientport, sock);

        // 将获取到的套接字添加到辅助数组里
        int pos = 1; // 从 1 开始 , 0 已经被监听套接字占用
        for (; pos < fd_num_max; ++pos)
        {
            if (_event_fds[pos].fd != defaultfd)
                continue;
            break;
        }
        if (pos == fd_num_max)
        {
            lg(WARNING, "server is full, close %d. ", sock);
            close(sock);
            // 可配合动态数组 如直接使用vector使得进行扩容
        }
        else
        {
            _event_fds[pos].fd = sock;
            _event_fds[pos].events = POLLIN; // 直接设置所关心事件
            DebugPrint();
        }
    }

    void Recver(int fd, int pos)
    {
        // 该程序只关心读事件
        char inbuff[1024];
        ssize_t n = read(fd, inbuff, sizeof(inbuff) - 1);
        // 直接调用read可能存在信息获取不完整等问题

        if (n > 0)
        { // 读取成功
            inbuff[n] = 0;
            printf("Get a massage for %d fd: %s\n", fd, inbuff);
        }
        else if (n == 0)
        { // 连接被关闭
            lg(INFO, "Fd %d connect closed", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd;
            _event_fds[pos].events = non_event;
        }
        else
        { // 读取失败
            lg(WARNING, "Fd %d recv error", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd;
            _event_fds[pos].events = non_event;
        }
    }

    void DebugPrint()
    {
        std::cout << "Fd List:" << std::endl;
        for (int i = 0; i < fd_num_max; ++i)
        {
            if (_event_fds[i].fd == defaultfd)
                continue;
            std::cout << "_event_fds[" << i << "].fd : " << _event_fds[i].fd << std::endl;
        }
        std::cout << std::endl;
    }

    void Dispatcher() // 事件派发器 将不同的事件派发给不同的模块
    {
        for (int i = 0; i < fd_num_max; ++i)
        {
            int fd = _event_fds[i].fd; // 取出数组中存储的描述符
            if (fd == defaultfd)
                continue; // 如果为默认fd则直接进行下一次循环

            if (_event_fds[i].revents & POLLIN) // 通过按位与的方式判断是否就绪
            {                                  
                if (fd == _listensock.GetFd()) // 如果描述符为监听套接字 则进行新连接的获取
                {
                    Accepter();
                }
                else
                { // 如果不为监听套接字则表示其他描述符的读事件已经就绪
                    Recver(fd, i);
                }
            }
        }
        // DebugPrint();
    }

    ~PollServer()
    {
        _listensock.Close();
    }

private:
    struct pollfd _event_fds[fd_num_max];
    NetSocket _listensock;
    uint16_t _port;
};
